var png_hero, png_tris, png_hash; //image handles
var snd_bgscore; //bgmusic handle
var canvas;
var ctx;
var g_mx=300, g_my=200; //global variables to hold the mouse posx and posy
var g_size = 32; //handles the scaling of images.
var g_player; //variable to hold player object
var g_enemyList = new Array(); 
var g_particleList = new Array(); 
var g_startGame = false;
var g_mesg;
var g_pausebutton;
var g_numHighScores = 5;

function RandChoice(list){
    var indx = Math.floor(Math.random() * list.length);
    return list[indx];
}


var MaxParticleSize = 30;
function Particle(x,y, vx, vy, color){
    this.x = x;
    this.y = y;
    this.vx = vx+RandChoice([-2, -1, 1, 2]);  
    this.vy = vy+RandChoice([-2, -1, 1, 2]);
    this.col = color.split('(')[1].split(')')[0];
    this.alpha = 1.0;
    this.size = 5;
    this.live = true;

    this.update = function(){
        this.x = this.x + this.vx;
        this.y = this.y + this.vy;
        this.alpha -= 0.05;
        if(this.alpha < 0.1){
            this.alpha = 0.1;
        }
        this.size += 1;
        if(this.size > MaxParticleSize){
            this.live = false;
        }
    }

    this.draw = function(){
        ctx.fillStyle = "rgba(" + this.col + "," + this.alpha +")";
        ctx.fillRect(this.x, this.y, this.size, this.size);
    }
}   //end Particle class

function AddBlast(e, color){
    for(var itr = 0; itr < 2; itr++){
        g_particleList.push(new Particle(e.x,e.y,-e.vx,-e.vy,color));
    }
}

//Player following update function 
function FollowPlayer(){
    var speed = 2;
    var dx = g_player.x - this.x;
    var dy = g_player.y  - this.y;
    var deno = Math.sqrt(dx * dx + dy*dy);
    this.vx = speed * dx/deno;
    this.vy = speed * dy/deno;
    this.x += this.vx; 
    this.y += this.vy; 
    this.angle = Math.atan2(dy,dx);
}

//bouncing around update function
function BounceAround(){
    var speed = 3;
    this.angle+= 0.1;
    if(this.vx == 0 || this.vy == 0)
    {
        this.vx = this.vy = speed;
    }
    this.x += this.vx;
    this.y += this.vy;

    if(this.x < 0 || this.x > canvas.width){
        this.vx = -this.vx;
        this.x += this.vx;
    }
    if(this.y < 0 || this.y > canvas.height){
        this.vy = -this.vy;
        this.y += this.vy;
    }
}

function Enemy(x, y, image, updatefunc) //enemy class
{
    this.x = x;
    this.y = y;
    this.vx = 0; 
    this.vy = 0;
    this.health = 100; 
    this.image = image;
    this.update = updatefunc;
    this.angle = 0;
    this.damage = 2;

    this.draw = function draw() {
        var min_alpha = 0.2;
        ctx.save();
        ctx.globalAlpha=(this.health+min_alpha)/100;
        ctx.translate(this.x, this.y);
        ctx.rotate(this.angle+3.14/2); 
        //ctx.drawImage(this.image, this.x-g_size/2, this.y-g_size/2, g_size, g_size);
        ctx.drawImage(this.image, -g_size/2, -g_size/2, g_size, g_size);
        ctx.restore();
    }
}

function Player() //player class 
{
    this.x = g_mx;
    this.y = g_my;
    this.radius = 60;
    this.image = png_hero;
    this.health = 100;
    this.score = 0;
    this.new_highScore = false;
    this.damage = 2;

    this.draw = function draw(){
        ctx.fillStyle="rgba(255,255,255,0.1)";
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, true);
        ctx.fill();
        ctx.globalAlpha = this.health / 100;
        ctx.drawImage(this.image, this.x-g_size/2, this.y-g_size/2, g_size, g_size);
        ctx.globalAlpha = 1.0;
    }

    this.isOverlap = function Overlap(obj){
        var dx = obj.x - this.x;
        var dy = obj.y - this.y;
        var norm = dx*dx + dy*dy;
        if (norm < (this.radius+g_size) * (this.radius+g_size))
        {
            if(norm < g_size * g_size)
            {//if you want to add power ups this is the place to write the code.
                this.health -= obj.damage;
                if(this.health % 5 == 0)
                    AddBlast(obj, "rgb(255,255,255)");
            }
            return true;
        }
        //else 
        return false;
    }
    this.update = function update(){
        this.x = g_mx;
        this.y = g_my;
    }
}

function onMouseMove(e){
	var posx = 0;
	var posy = 0;

    if (e.pageX || e.pageY){
        posx = e.pageX;
        posy = e.pageY;
    }
    else if (e.clientX || e.clientY){
        posx = e.clientX + document.body.scrollLeft
            + document.documentElement.scrollLeft;
        posy = e.clientY + document.body.scrollTop
            + document.documentElement.scrollTop;
    }
    // posx and posy contain the mouse position relative to the document
    // Do something with this information
    g_mx = (posx-canvas.offsetLeft); 
    g_my = (posy-canvas.offsetTop);
}

function draw() //game draw cycle.
{
    if(!g_startGame)//dont' start the game unless start is pressed.
        return;
    var radius = 60;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    g_player.draw();
    for(i in g_enemyList)
    {
        g_enemyList[i].draw();
    }
    //drawing particles on top of everything.
    for(var i in g_particleList){
        g_particleList[i].draw();
    }
    
}

var g_TextMessage;
function TextMessage(id){
    this.box = document.getElementById(id);
    this.init = function(txt){
        this.live = true;
        this.start = new Date();
        //this.text = txt;
        this.box.innerHTML=txt;
        this.box.style.visibility="visible";
    }

    this.update = function(){
        if(!this.live)
            return;
        var cur = new Date();
        if((cur - this.start) > 2000){
            this.box.style.visibility="hidden";
            this.live=false;
        }
    }
}

var g_highScores = new Array();
var g_hsNames = new Array();
function saveHighScores()
{ //save the highscores to local store.
    var score_set = false;
    var hs = new Array();
    var hsn = new Array();
    for(var i = 0, j = 0; i < g_numHighScores; i++)
    {
        if(g_highScores[j] < g_player.score && score_set==false)
        {
            hs.push(g_player.score);
            hsn.push(document.getElementById("pname").value);
            score_set = true;
        }
        else
        {
            hs.push(g_highScores[j]);
            hsn.push(g_hsNames[j]);
            j++;
        } 
    }
    document.getElementById("hsbutton").value="saved";
    document.getElementById("hsbutton").disabled=true;
    window.localStorage['highscores'] = hs;
    window.localStorage['hsnames'] = hsn;
}

function getHighScores()
{
    var score_set = false;
    var str = '<table>'
    for(var i = 0, j = 0; i < g_numHighScores; i++)
    {
        if(g_highScores[j] < g_player.score && score_set==false)
        {
            str += "<tr><td><input type=text value=\"---\" id=\"pname\">";
            str += "<input type=button value=\"submit\" id=\"hsbutton\" onClick=\"saveHighScores();\"></td><td>"+g_player.score+"</td>";
            score_set = true;
        }
        else
        {
            str += '<tr><td>'+g_hsNames[j]+"</td><td>"+g_highScores[j]+"</td></tr>";
            j++;
        } 
    }
    str += '</table>';
    return str;
}

function update() //game update cycle.
{
    if(!g_startGame)//dont' start the game unless start is pressed.
        return;
    EnemyGenerator();
    g_player.update();
    var tmp = new Array();
    for(i in g_enemyList)
    {
        g_enemyList[i].update();
        if(g_player.isOverlap(g_enemyList[i]))
        {//enemy is in the disintegration range.
            g_enemyList[i].health -= g_player.damage;
            if(g_enemyList[i].health % 5 == 0)
                AddBlast(g_enemyList[i], "rgb(255,0,0)");
        }
        if(g_enemyList[i].health > 0)
        {            
            tmp.push(g_enemyList[i]);
        }
        else
        {//an enemy died.. add score.
            g_player.score += 10;// vary based on enemies.
            //check if we are above the min high score.
            if(!g_player.new_highScore && g_player.score > g_highScores[4])
            {
                //show the player that they made a new high score.
                g_TextMessage.init("New High Score");
                g_player.new_highScore = true;
            }
            if(g_player.health < 100)
                g_player.health += 1; 
        }
    }
    g_enemyList = tmp;
    //check if the game is over.
    if(g_player.health < 0){
        //check the previous scores.
        //set the current score if greater than any high score.
        g_startGame = false;
        g_pausebutton.style.visibility = "hidden";
        var d = new Date();
        g_mesg.innerHTML='<b>Game Over</b><br/> <table><tr><td>Score:</td><td>'+ g_player.score +
            '</td></tr><tr><td>Time:</td><td>' + (d.getTime() - g_startTime)/1000 +
            ' secs </td></tr></table><br/><b>HighScores:</b><br/>'+ getHighScores() + 
            '<input type="button" value="Restart" onClick="window.location.reload()">';
        g_mesg.style.top=100;
        g_mesg.style.left=120;
        g_mesg.style.height=300;
        g_mesg.style.width=400;
        g_mesg.style.visibility="visible";
    }
    var tmp = new Array();
    for(var i in g_particleList){
        g_particleList[i].update();
        if(g_particleList[i].live)
            tmp.push(g_particleList[i]);
    }
    g_particleList = tmp;
    //ui handler for showing in game messages.
    g_TextMessage.update();
}

function GameLoop()
{
    update();
    draw();
}

function StartGame()
{
    snd_bgscore.play(); 
    g_startGame=true;
    g_mesg.style.visibility="hidden";
    g_pausebutton.style.visibility="visible";
}

function PauseButtonClicked()
{
    if(g_pausebutton.value== "||")
    {
        g_pausebutton.value=">";
        snd_bgscore.pause();
        g_startGame=false;
        g_mesg.innerHTML="Paused";
        g_mesg.style.visibility="visible";
    }
    else
    {
        g_mesg.style.visibility="hidden";
        g_pausebutton.value="||";
        snd_bgscore.play();
        g_startGame=true;
    }
}

var g_time;
var g_startTime;
function EnemyGenerator(){
    g_time += 1;
    var time_check = 60;
    if(g_time > 5) // after 5 seconds)
    {
        time_check = 30;
        if(g_time > 20)
        {
            time_check = 15;
        }
    }
    if(g_time % time_check == 0){ //multiples of 30 i.e, once per second
            var pos = [0, 640, 480, 250];
            var t = [
                function(){g_enemyList.push(new Enemy(RandChoice(pos), RandChoice(pos), png_tris, FollowPlayer));}, 
                function(){g_enemyList.push(new Enemy(RandChoice(pos), RandChoice(pos), png_hash, BounceAround));}
            ]
                f = RandChoice(t);
            f();
    }
}

function LoadingDone()
{
    //all are loaded get rid of the loading gif
    var spinner = document.getElementById("gif_spinner");
    spinner.style.visibility="hidden";
    g_mesg = document.getElementById("mesg");
    g_mesg.innerHTML="<input style='height:30;' type=button value='Start' onClick='StartGame();'>";
    g_mesg.style.visibility="visible";
    g_pausebutton = document.getElementById("button_pause");
    //start the game related init.
    png_hero = document.getElementById("png_hero");
    png_tris = document.getElementById("png_tris");
    png_hash = document.getElementById("png_hash");
    snd_bgscore = document.getElementById("snd_bgscore");
    canvas = document.getElementById("canv");
    canvas.style.visibility="visible";
    canvas.onmousemove=onMouseMove;
    ctx = canvas.getContext('2d');
    //load the previous high scores
    var hs = window.localStorage["highscores"];
    var hsn = window.localStorage["hsnames"];
    if(hs && hsn){//we are loading previous data
        g_highScores = hs.split(',');
        g_hsNames = hsn.split(',');
            for(var i in g_highScores){
                g_highScores[i] = parseInt(g_highScores[i]);
            }
    }else{  //we are running for the first time.
        for(var i = 0; i < g_numHighScores; i++){
            g_highScores.push(0);
            g_hsNames.push('---');
        }
    }
    //---done..
    //create the player object
    g_player = new Player();
    g_TextMessage = new TextMessage("gmesg");
    //enemy object
    g_enemyList.push(new Enemy(0, 0, png_tris, FollowPlayer));
    var FPS = 30.0;
    g_time = 0;
    var d = new Date();
    g_startTime = d.getTime();
    setInterval(GameLoop, 1000/FPS);
}
